/********************************************************************************
 * Copyright (c)2016-2020, ShenZhen WanJiaAn Technology CO.,LTD.
 * All Rights Reserved.
 *
 * File Name     : McuUpdate.c
 * Author        : joki.zhu
 * Date          : 2020-03-03
 *
 * Record        :
 * 1.Date        : 2020-03-03
 *   Author      : joki.zhu
 *   Modification: Created file
 ********************************************************************************/
#include <stdio.h>
#include <string.h>
#include "McuUpdate.h"
#include "mcu_update_msg.h"
#include "DevGpio.h"
#include "ProductManager.h"

#define MCU_UPDATE_PER_DATA_SIZE	(512)	//MCU每个升级数据大小,单位bytes

static char gs_bMcuUpdateRun = 0;

static int mcu_reset(void)
{
    printf("%s\n", __FUNCTION__);

    /* keep self power */
    GpioSet(PRODUCT_GPIO_KEEP_SELF_POWER);
    usleep(3 * 1000);

    /* rest mcu */
    GpioSet(PRODUCT_GPIO_RESET_MCU);
    usleep(50 * 1000);
    GpioReset(PRODUCT_GPIO_RESET_MCU);

    return 0;	
}

static int mcu_send_update_start(void)
{
    printf("%s\n", __FUNCTION__);
    
    int ret = 0;
    UARTMSG_PARM_S stSendMsg;
    UARTMSG_PARM_S stWaitMsg;
    
    memset(&stSendMsg, 0, sizeof(stSendMsg));
    memset(&stWaitMsg, 0, sizeof(stWaitMsg));
    stSendMsg.u32MsgId = UARTMSG_S2M_UPGRADE_START;
    stWaitMsg.u32MsgId = UARTMSG_M2S_UPGRADE_START_ACK;
    ret = UartMsgSendMsgAndWaitMsg(&stSendMsg, &stWaitMsg, 500);
    if (ret < 0) {
        printf("UartMsgSendMsgAndWaitMsg failed\n");
#ifndef JOKI_DEBUG        
        return -1;
#endif  
    }
    
    return 0;
}

static int mcu_send_update_params(int pktSize)
{
    printf("%s\n", __FUNCTION__);
    
    int ret = 0;
    UARTMSG_PARM_S stSendMsg;
    UARTMSG_PARM_S stWaitMsg;
    
    memset(&stSendMsg, 0, sizeof(stSendMsg));
    memset(&stWaitMsg, 0, sizeof(stWaitMsg));
    stSendMsg.u32MsgId = UARTMSG_S2M_UPGRADE_PARAMS;
    stWaitMsg.u32MsgId = UARTMSG_M2S_UPGRADE_PARAMS_ACK;
    stSendMsg.data[0] = (pktSize + MCU_UPDATE_PER_DATA_SIZE - 1) / MCU_UPDATE_PER_DATA_SIZE;
    stSendMsg.dataLen = 1;
    
    ret = UartMsgSendMsgAndWaitMsg(&stSendMsg, &stWaitMsg, 500);
    if (ret < 0) {
        printf("UartMsgSendMsgAndWaitMsg failed\n");
#ifndef JOKI_DEBUG        
        return -1;
#endif        
    }
    
    return 0;
}

static int mcu_send_update_data(unsigned char index, unsigned char *pDataBuf, int dataSize)
{
    printf("%s\n", __FUNCTION__);
    
    int ret = 0;
    UARTMSG_PARM_S stSendMsg;
    UARTMSG_PARM_S stWaitMsg;
    
    memset(&stSendMsg, 0, sizeof(stSendMsg));
    memset(&stWaitMsg, 0, sizeof(stWaitMsg));
    stSendMsg.u32MsgId = index;
    stWaitMsg.u32MsgId = index;
    memcpy(stSendMsg.data, pDataBuf, dataSize);
    stSendMsg.dataLen = dataSize;
    
    ret = UartMsgSendMsgAndWaitMsg(&stSendMsg, &stWaitMsg, 500);
    if (ret < 0) {
        printf("UartMsgSendMsgAndWaitMsg failed\n");
#ifndef JOKI_DEBUG        
        return -1;
#endif        
    }
    
    return 0;

}

static int mcu_send_update_end()
{
    printf("%s\n", __FUNCTION__);
    
    int ret = 0;
    UARTMSG_PARM_S stSendMsg;
    UARTMSG_PARM_S stWaitMsg;
    
    memset(&stSendMsg, 0, sizeof(stSendMsg));
    memset(&stWaitMsg, 0, sizeof(stWaitMsg));
    stSendMsg.u32MsgId = UARTMSG_S2M_UPGRADE_END;
    stWaitMsg.u32MsgId = UARTMSG_M2S_UPGRADE_END_ACK;
    ret = UartMsgSendMsgAndWaitMsg(&stSendMsg, &stWaitMsg, 500);
    if (ret < 0) {
        printf("UartMsgSendMsgAndWaitMsg failed\n");
#ifndef JOKI_DEBUG        
        return -1;
#endif        
    }
    
    return 0;
}

int McuUpdateInit(char *crc)
{
    if (crc == NULL) {
        printf("Params is invalid %s\n", __FUNCTION__);
        return -1;
    }

    printf("%s\n", __FUNCTION__);

    /* check whether the mcu supports online upgrade */
    if (SocSubCheckIsSupportUpdate() == 0) {
       printf("the mcu dont't support update!!!\n");
       return -1;
    }
    
    /* check mcu crc is equal */
    char mcuConfigCrc[12] = "";
    DevConfigGetMcuCrc(mcuConfigCrc, sizeof(mcuConfigCrc));
    if (strcmp(mcuConfigCrc, crc) == 0) {
        printf("mcu crc is euqal, exit mcu upgrade!\n");
        return -1;
    }
    
    gs_bMcuUpdateRun = 1;

#ifndef MINI_APP
        #ifdef ZDK_PROTOCOL
        RealTimeServerClose();
        #endif
#endif /* MINI_APP */

    WifiStopStaMode();
    
    /* close mcu wdt */
    SocSubSetWdgState(0);
    
    
    HI_HAL_UART_SetPause(1);
    sleep(3);
    UartMsgInit();
    
    return 0;
}

int McuUpdateRun(unsigned char *pPktData, int pktSize)
{
    printf("%s\n", __FUNCTION__);

    int i = 0;
    int ret = 0;
    unsigned char index = 0x00;
    int remainSize = 0;
    int copyOffset = 0;
    int sendSize = 0;
    unsigned char dataBuf[MCU_UPDATE_PER_DATA_SIZE] = {0};

reset_again:

    //01. 复位mcu
    printf("reset mcu!\n");
    mcu_reset();
    
    //02. 发送升级请求
    i = 0;
    for (i = 0; i < 6; i++)
    {
        ret = mcu_send_update_start(); //发送超时为500ms
        if (ret >= 0) {
            break;
        }
    }
    if (i == 6) { //6*500ms = 3s, 升级请求失败超过3s,重新复位mcu
        usleep(10 * 1000);
        goto reset_again;
    }

//	return 0;
	
    //03. 设置升级参数
    i = 0;
    for (i = 0; i < 3; i++)
    {
        ret = mcu_send_update_params(pktSize); //等待确认结果超时为100~200ms
        if (ret >= 0) {
            break;
        }
    }
	
    if (i == 3) { //设置参数失败超过3次,重新复位mcu
        goto reset_again;
    }
	
    //04. 发送升级数据
    index = 0x00;
    copyOffset = 0;
    remainSize = pktSize;
    while (remainSize > 0)
    {
        if (remainSize < MCU_UPDATE_PER_DATA_SIZE) {
        	sendSize = remainSize;
        } else {
        	sendSize = MCU_UPDATE_PER_DATA_SIZE;
        }
        memset(dataBuf, 0x00, sizeof(dataBuf));
        memcpy(dataBuf, pPktData + copyOffset, sendSize);
        ret = mcu_send_update_data(index, dataBuf, sendSize); //等待确认结果超时为100ms
        if (ret < 0) {
            goto reset_again;
        }
        index++;
        copyOffset += sendSize;
        remainSize -= sendSize;
		printf("copyOffset %d sendSize %d\n", copyOffset, sendSize);
    }
	
    //05. 发送升级结束
    ret = mcu_send_update_end(); //等待确认结果超时100ms
    if (ret < 0) {
        //goto reset_again;
        sleep(3);
    }

    printf("mcu upgrade success!\n");

    return 0;
}

int McuUpdateCheckIsRunning(void)
{
    return gs_bMcuUpdateRun;
}

int McuUpdateDeinit(char *crc)
{
    if (crc == NULL) {
        printf("Params is invalid %s\n", __FUNCTION__);
        return -1;
    }
    printf("%s\n", __FUNCTION__);
    
    /* update mcu crc to config */
    DevConfigSetMcuCrc(crc);
    
    /* dont't keep self power */
    GpioReset(PRODUCT_GPIO_KEEP_SELF_POWER);
    usleep(10 * 1000);

    /* reset mcu */
    GpioSet(PRODUCT_GPIO_RESET_MCU);
    usleep(50 * 1000);
    GpioReset(PRODUCT_GPIO_RESET_MCU);
    
    return 0;
}

#if 0
int main(int argc, const char *argv[])
{
#if 1
	if (argc < 2) {
		printf("Usage: %s [file]\n", argv[0]);
		return -1;
	}

	unsigned char *pBuf = NULL;
	FILE *fp = NULL;
	int readLen = 0;
	int readOffset = 0;
	int pktSize = 0;

	pBuf = (unsigned char *)malloc(64 * 1024);
	if (pBuf == NULL) {
		printf("malloc failed\n");
		return -1;
	}
	
	memset(pBuf, 0, 64 * 1024);

	fp = fopen(argv[1], "rb");
	if (fp == NULL) {
		perror(argv[1]);
		return -1;
	}

	while (1)
	{
		readLen = fread(pBuf + readOffset, 1, 1024, fp);
		if (readLen == 0) {
			fclose(fp);
			break;
		}
		readOffset += readLen;
		pktSize += readLen;
	}

	printf("pktSize: %d\n", pktSize);
	McuUpdateRun(pBuf, pktSize);
#else
    unsigned char pktData[32] = {0x00, 0x11, 0x22, 0x33, 0x44};
    
	McuUpdate(pktData, sizeof(pktData));
#endif
	return 0;
}
#endif

